package com.qkl.user.controller;

import com.qkl.user.dto.ExceptionResponse;
import com.qkl.user.exception.OperationException;
import org.web3j.abi.FunctionReturnDecoder;
import org.web3j.abi.datatypes.Address;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.generated.Uint256;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.request.Transaction;
import org.web3j.protocol.core.methods.response.EthCall;
import org.web3j.protocol.core.methods.response.EthGetBalance;
import org.web3j.protocol.http.HttpService;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collections;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
import org.web3j.abi.datatypes.Function;

@Slf4j
@RestController
@RequestMapping("bsc")
public class BscController {
    //https://testnet.bscscan.com/
    //0xc449b86870C49C8b555c8f5973f70F6EB88C7915
    //0xD6AeC6Cd8727f7dE3189fCA6A2b401CD02Bf85BE
    @GetMapping("getBnbBalance")
    public ResponseEntity<ExceptionResponse> getBnbBalance(@RequestParam(value = "address",defaultValue = "") String address) throws ExecutionException, InterruptedException {
        if(address == null || address.isEmpty()){
            throw new OperationException(-1,"请输入地址");
        }
        log.info(address);
        Web3j web3j = Web3j.build(new HttpService("https://data-seed-prebsc-2-s1.bnbchain.org:8545"));//https://bsc.blockrazor.xyz
        DefaultBlockParameter blockParam = DefaultBlockParameterName.LATEST;
        EthGetBalance balanceResponse = web3j.ethGetBalance(address, blockParam).sendAsync().get();
        BigInteger balanceWei = balanceResponse.getBalance(); // 余额（Wei单位）
        HashMap<String,Object> map = new HashMap<>();
        map.put("balance", new BigDecimal(balanceWei).divide(new BigDecimal("1e18")));
        map.put("address", address);
        return ResponseEntity.ok(ExceptionResponse.Success(map));
    }

    @GetMapping("getErc20Balance")
    public ResponseEntity<ExceptionResponse> getErc20Balance(
            @RequestParam(value = "address",defaultValue = "") String address,
            @RequestParam(value = "contractAddress",defaultValue = "") String contractAddress,
            @RequestParam(value = "decimals",defaultValue = "18") Integer decimals) throws ExecutionException, InterruptedException {
        if(address == null || address.isEmpty()){
            throw new OperationException(-1,"请输入地址");
        }
        if(contractAddress == null || contractAddress.isEmpty()){
            throw new OperationException(-1,"请输入合约地址");
        }
        if(decimals == null|| decimals <= 0){
            throw new OperationException(-1,"请输入精度");
        }
        Web3j web3j = Web3j.build(new HttpService("https://data-seed-prebsc-2-s1.bnbchain.org:8545"));
        DefaultBlockParameter blockParam = DefaultBlockParameterName.LATEST;
        // 构造ERC20的balanceOf函数调用
        Function function = new Function(
                "balanceOf",
                Collections.singletonList(new Address(address)), // 参数：钱包地址
                Collections.singletonList(new TypeReference<Uint256>() {}) // 返回值：uint256
        );
        String encodedFunction = FunctionEncoder.encode(function);
        // 调用合约
        EthCall response = web3j.ethCall(
                Transaction.createEthCallTransaction(null, contractAddress, encodedFunction),
                blockParam
        ).sendAsync().get();

        // 解析返回结果（Wei单位，需除以代币小数位）
        BigInteger balanceWei = (BigInteger) FunctionReturnDecoder.decode(
                response.getValue(), function.getOutputParameters()
        ).getFirst().getValue();
        BigDecimal balance = new BigDecimal(balanceWei).divide(BigDecimal.valueOf(Math.pow(10, decimals)));
        return ResponseEntity.ok(ExceptionResponse.Success(balance));
    }
}
